﻿/*
 * ControlConsole.cs
 * 
 * Purpose:
 * User interface form
 * 
 * Revision Log:
 * 02-SEP-12, Q. Nguyen, First Draft.
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Collections;

using Air_Trafic_Control.Domain.Control;
using Air_Trafic_Control.Domain.Util;
using Air_Trafic_Control.Domain.Common;
using Air_Trafic_Control.Domain.Entity;
using Air_Trafic_Control.Domain.Persistence;

namespace Air_Trafic_Control.UI
{
    //public delegate void UpdateDelegate();

    public partial class ControlConsole : Form
    {
        private static Logger log = new Logger(typeof(ControlConsole));

        private Image m_BaseImage = null;
        private float m_rotateAngleInDegree = 0f;
        private int m_ScreenDiameter = 0;
        private int m_ScreenRadious = 0;
        private Point m_ScreenCenter;
        //Drawpath is a connection of all drawing lines together to guide the artist's hand
        private GraphicsPath m_ScanLineSketch = null;
        private GraphicsPath m_AircraftSymbolSketch = null;
        private Rectangle m_rec;
        private ptAboutATC m_formAboutATC;
        private NewGame m_formNewGame;
        //private AboutATC 
        private EAT m_eat;
        private ArrayList m_InRangeAircrafts;
        

        //public event UpdateDelegate ScreenUpdateEvent;

        //Form constructor
        public ControlConsole()
        {
            m_eat = EAT.GetEAT();

            InitializeComponent();


            m_ScreenDiameter = this.pictureBox1.Width;
            m_ScreenRadious = m_ScreenDiameter / 2;
            m_ScreenCenter = new Point(pictureBox1.Width / 2, pictureBox1.Width / 2);

            CreateScanLineSketch();
            CreateAircratSketch();

            m_formAboutATC = new ptAboutATC();
            m_formNewGame = new NewGame();
        }

        #region Private methods

        /// <summary>
        /// This is event handler for form loading for the first time. 
        /// It draw the display screen to pictureBox1
        /// </summary>
        private void DrawDisplayScreen(object sender, EventArgs e)
        {
            Color topColor = Color.FromArgb(0, 120, 0);
            Color bottomColor = Color.FromArgb(0, 40, 0);
            Color lineColor = Color.FromArgb(0, 255, 0);//Green color
            Color airportLineColor = Color.FromArgb(255, 0, 0);//Red

            //Create a bitmap image object to draw on. It basically a canvast with top left conner has coordinate of 0,0.
            m_BaseImage = new Bitmap(m_ScreenDiameter, m_ScreenDiameter);
            //Creat a graphics object (artist) that associated with the new image to draw on the image object later
            Graphics Artist = Graphics.FromImage(m_BaseImage);
            //Create a pen object
            Pen DrawingPen = new Pen(lineColor);
            Pen AirportPen = new Pen(airportLineColor);
            //Create a brush object
            LinearGradientBrush DrawingBrush = new LinearGradientBrush(new Point(m_ScreenRadious, 0), new Point(m_ScreenRadious, m_ScreenDiameter - 1), topColor, bottomColor);
            // set a couple of graphics properties to make the
            // output image look nice. "set up a good artist"
            Artist.CompositingQuality = CompositingQuality.HighQuality;
            Artist.InterpolationMode = InterpolationMode.Bicubic;
            Artist.SmoothingMode = SmoothingMode.AntiAlias;
            Artist.TextRenderingHint = TextRenderingHint.AntiAlias;
            //Paint the background of the radar
            Artist.FillEllipse(DrawingBrush, 0, 0, m_ScreenDiameter - 1, m_ScreenDiameter - 1);
            //Tell the artist to draw the outer ring
            Artist.DrawEllipse(DrawingPen, 0, 0, m_ScreenDiameter - 1, m_ScreenDiameter - 1);
            //tell the artist to draw the inner ring 
            int interval = m_ScreenDiameter / 3;
            Artist.DrawEllipse(DrawingPen, (m_ScreenDiameter - interval) / 2, (m_ScreenDiameter - interval) / 2, interval, interval);
            // tell the artist to draw the middle ring
            interval *= 2;
            Artist.DrawEllipse(DrawingPen, (m_ScreenDiameter - interval) / 2, (m_ScreenDiameter - interval) / 2, interval, interval);

            // Draw the airport ring
            interval = Constants.SYS_AIRPORT_DIAMETER;
            Artist.DrawEllipse(AirportPen, (m_ScreenDiameter - interval) / 2, (m_ScreenDiameter - interval) / 2, interval, interval);

            // tell the artist to draw the x and y axis lines
            Artist.DrawLine(DrawingPen, new Point(0, m_ScreenRadious), new Point(m_ScreenDiameter - 1, m_ScreenRadious));
            Artist.DrawLine(DrawingPen, new Point(m_ScreenRadious, 0), new Point(m_ScreenRadious, m_ScreenDiameter - 1));

            // release the artist (graphics object)
            Artist.Dispose();
            // copy the newly drawn base image to pictureBox1
            pictureBox1.Image = m_BaseImage;
        }

        private void DrawScanLine(Graphics g)
        {
            if (m_rotateAngleInDegree < 360f)
            {
                m_rotateAngleInDegree += 3f;
            }
            if (m_rotateAngleInDegree == 360f)
            {
                m_rotateAngleInDegree = 0f;
            }
            g.ResetTransform();
            g.TranslateTransform(m_ScreenCenter.X, m_ScreenCenter.Y);
            g.RotateTransform(m_rotateAngleInDegree);
            g.DrawPath(new Pen(Color.GreenYellow, 1f), m_ScanLineSketch);
        }

        private void StartButton_Click(object sender, EventArgs e)
        {
            // Is there a game loaded?
            if (this.m_eat.SelectedGame == null)
            {
                // If there is no game loaded, redirect to the new game screen
                miNewGame_Click(sender, e);

                // Exit this method
                return;
            }
            if (this.m_eat.StartTime == DateTime.MinValue) 
                this.m_eat.StartTime = DateTime.Now.Subtract(System.TimeSpan.FromSeconds(this.m_eat.SelectedGame.RunTime));

            //The button is at off state
            if (!this.timer1.Enabled)
            {
                if (this.m_eat.PauseTime != DateTime.MinValue)
                {
                    TimeSpan elapsedPaused = DateTime.Now.Subtract(this.m_eat.PauseTime);
                    this.m_eat.StartTime = this.m_eat.StartTime.Add(elapsedPaused);
                }
                this.timer1.Interval = 60;
                this.timer1.Enabled = true;
                this.m_eat.EATTimerInterval = 100;
                this.m_eat.EATTimerEnabled = true;
                this.m_eat.SelectedGame.GameTimerEnable = true;
                this.m_eat.SelectedGame.OnStartButton(true);
                this.StartButton.Text = "Pause";
                this.StartButton.ForeColor = Color.Red;
                log.Info("Enabled");
            }
            //The button is at on state
            else
            {
                this.timer1.Enabled = false;
                this.m_eat.EATTimerEnabled = false;
                this.m_eat.SelectedGame.GameTimerEnable = false;
                this.m_eat.SelectedGame.OnStartButton(false);
                this.StartButton.Text = "Start";
                this.StartButton.ForeColor = Color.Black;
                this.m_eat.PauseTime = DateTime.Now;
            }

        }

        private void miNewGame_Click(object sender, EventArgs e)
        {
            if (this.m_eat.SelectedGame != null)
                if (timer1.Enabled == true)
                    StartButton_Click(sender, e);
            m_formNewGame.Reset();
            m_formNewGame.Show();
        }

        private void miExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void loadGameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.m_eat.SelectedGame != null)
                if (timer1.Enabled == true)
                    StartButton_Click(sender, e);
            ptLoadGame pt1 = new ptLoadGame();
            pt1.Show();
        }

        private void CreateScanLineSketch()
        {
            Rectangle m_rec = new Rectangle(0, 0, m_ScreenRadious, 1);
            m_ScanLineSketch = new GraphicsPath();
            m_ScanLineSketch.AddRectangle(m_rec);
        }

        private void CreateAircratSketch()
        {
            Point[] polyPoints = { new Point(0, -10), new Point(10, 10), new Point(0, 5), new Point(-10, 10) };
            m_AircraftSymbolSketch = new GraphicsPath();
            m_AircraftSymbolSketch.AddPolygon(polyPoints);
        }

        private void DrawAircraftSymbol(Graphics g)
        {
            if (m_InRangeAircrafts != null)
            {
                foreach (FlyObject fObj in this.m_InRangeAircrafts)
                {
                    g.ResetTransform();

                    // Adjust the angle for the radar image
                    g.TranslateTransform(fObj.OwnPosition.X, fObj.OwnPosition.Y);
                    g.RotateTransform(fObj.Heading + fObj.RotationAdjustment);
                    if (fObj.IsSelected)
                    {
                        g.DrawPath(new Pen(Color.Red, 2f), m_AircraftSymbolSketch);
                    }
                    else
                    {
                        g.DrawPath(new Pen(Color.DarkOrange, 2f), m_AircraftSymbolSketch);
                    }
                }
            }
        }

        /// <summary>
        /// Form timer tick event handler
        /// </summary>
        private void OnDraw()
        {
            // create a copy of the base image to draw on
            Image CopiedImage = new Bitmap(m_BaseImage);
            // create a local artist (graphic object) to draw on the copied image
            Graphics Artist = Graphics.FromImage(CopiedImage);
            // set a couple of graphics properties to make the
            // output image look nice(Set the quality of the artist)
            Artist.CompositingQuality = CompositingQuality.HighQuality;
            Artist.InterpolationMode = InterpolationMode.Bicubic;
            Artist.SmoothingMode = SmoothingMode.AntiAlias;
            Artist.TextRenderingHint = TextRenderingHint.AntiAlias;

            DrawScanLine(Artist);

            DrawAircraftSymbol(Artist);

            // release the graphics object (local artist)
            Artist.Dispose();
            pictureBox1.Image = CopiedImage;

            this.txtLandedNumber.Text = this.m_eat.LandedPlanes.ToString();
            this.txtCrashedNumber.Text = this.m_eat.CrashedPlanes.ToString();
            this.txtLevel.Text = this.m_eat.SelectedGame.DifficultyLevel.ToString();
            TimeSpan elapseTime = DateTime.Now.Subtract(this.m_eat.StartTime);
            this.m_eat.SelectedGame.RunTime = elapseTime.TotalSeconds;
            this.txtTimeElapsed.Text  = String.Format("{0,2:00}:{1,2:00}:{2,2:00}", elapseTime.Hours, elapseTime.Minutes, elapseTime.Seconds);

            if (this.m_eat.SelectedGame.SelectedFlyingObject == null)
            {
                this.txtType.Text = "";
                this.txtTailNumber.Text = "";
                this.txtHeading.Text = "";
                this.txtSpeed.Text = "";
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (this.timer1.Enabled)
            {
                m_InRangeAircrafts = m_eat.GetAircrafts();
                OnDraw();
            }
        }

        private void aboutATCSimToolStripMenuItem_Click(object sender, EventArgs e)
        {
            m_formAboutATC.Show();
        }

        private void saveGameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.m_eat.SelectedGame != null)
            {
                GamePersistenceHandler gph = this.m_eat.GetGamePersistenceHandler();
                if (gph != null)
                {
                    bool success;

                    // Update the entity
                    for (int i = 0; i < gph.Games.Count; i++)
                    {
                        if (gph.Games[i].Name.Equals(this.m_eat.SelectedGame.Name))
                        {
                            gph.Games[i] = this.m_eat.SelectedGame;
                        }
                    }

                    success = gph.SaveGames();
                    if (success)
                    {
                        MessageBox.Show("Your game was successfully saved!", "Save Game", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                    else
                    {
                        MessageBox.Show("An error was encountered while trying to save your game. It may not have saved.", "Save Game", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }

            }
        }

        private void UpdateInformation()
        {
            FlyObject fobj = null;

            // Set fobj
            if (this.m_eat.SelectedGame != null && this.m_eat.SelectedGame.SelectedFlyingObject != null)
            {
                fobj = this.m_eat.SelectedGame.SelectedFlyingObject;
            }

            // Update
            if (fobj != null)
            {
                //Update the text of the fly object type
                this.txtType.Text = fobj.FlyObjTypeName;
                this.txtTailNumber.Text = fobj.TailNumber.ToString();
                this.txtSpeed.Text = fobj.Speed.ToString();

                // Add 90 to all headings because the angle used to draw the image subtracts 90 to
                // get the image right. Adjust the heading so it is always a positive number.
                if (fobj.Heading < 0)
                {
                    if ((fobj.Heading + 450) > 360)
                    {
                        this.txtHeading.Text = (fobj.Heading + 90).ToString();
                    }
                    else
                    {
                        this.txtHeading.Text = (fobj.Heading + 450).ToString();
                    }
                }
                else
                {
                    this.txtHeading.Text = (fobj.Heading + 90).ToString();
                }
            }
        }

        #endregion

        #region Public Methods
       /*
        public void pictureBox1_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            this.txtType.Text = "";
            this.txtTailNumber.Text = "";
            this.txtHeading.Text = "";
            this.txtSpeed.Text = "";
            if (this.m_eat != null && this.m_eat.SelectedGame != null)
            {
               this.m_eat.SelectedGame.SelectedFlyingObject = null;
            }

            if (m_InRangeAircrafts != null)
            {
                foreach (FlyObject fobj in m_InRangeAircrafts)
                {
                    fobj.IsSelected = false;
                        if (fobj.symRectangle.Contains(e.X, e.Y))
                        {
                            if (this.m_eat.SelectedGame.SelectedFlyingObject == null)
                            {
                                this.m_eat.SelectedGame.SelectedFlyingObject = fobj;
                                fobj.IsSelected = true;
                                UpdateInformation();
                            }
                        }
                }
            }
        }*/


        public void pictureBox1_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
           ResetTextBoxes();

           if (this.m_eat != null && this.m_eat.SelectedGame != null)
           {
              this.m_eat.SelectedGame.SelectedFlyingObject = null;
           }

           if (m_InRangeAircrafts != null && e != null)
           {
              foreach (FlyObject fobj in m_InRangeAircrafts)
              {
                 if (fobj != null && fobj.symRectangle != null)
                 {
                    fobj.IsSelected = false;
                    if (fobj.symRectangle.Contains(e.X, e.Y))
                    {
                       if (m_eat != null && m_eat.SelectedGame != null)
                       {
                          this.m_eat.SelectedGame.SelectedFlyingObject = fobj;
                       }
                       fobj.IsSelected = true;

                       UpdateInformation();
                    }
                 }
              }
           }
        }

        private void ResetTextBoxes()
        {
           this.txtType.Text = "";
           this.txtTailNumber.Text = "";
           this.txtHeading.Text = "";
           this.txtSpeed.Text = "";
        }

        public void ControlConsole_KeyDown(object sender, KeyEventArgs e)
        {
            if (this.m_eat.SelectedGame != null && this.m_eat.SelectedGame.SelectedFlyingObject != null)
            {
                switch (e.KeyCode)
                {
                    case Keys.Left:
                        {
                            this.m_eat.SelectedGame.SelectedFlyingObject.Heading -= Constants.SYS_HEADING_ADJUSTMENT_INCREMENT;
                            UpdateInformation();
                            break;
                        }

                    case Keys.Right:
                        {
                            this.m_eat.SelectedGame.SelectedFlyingObject.Heading += Constants.SYS_HEADING_ADJUSTMENT_INCREMENT;
                            UpdateInformation();
                            break;
                        }

                    case Keys.Up:
                        {
                            this.m_eat.SelectedGame.SelectedFlyingObject.Speed += Constants.SYS_SPEED_ADJUSTMENT_INCREMENT;
                            UpdateInformation();
                            break;
                        }

                    case Keys.Down:
                        {
                            this.m_eat.SelectedGame.SelectedFlyingObject.Speed -= Constants.SYS_SPEED_ADJUSTMENT_INCREMENT;
                            UpdateInformation();
                            break;
                        }
                }
            }
        }

        #endregion
    }
}



